package zdar.entities;

/**
 * This class represents the physical embodiment of a UnitTemplate and contains changeable variables like wound count and whether or not they are alive.
 * While things like Agility and Abilities are permanent for now, eventually we will need to work in Items (each has their own ability set) and Level ups (with stat changes)
 * If a stat is changed for a Unit, it doesn't change it for the unit template does it? No... so I don't see what the problem is, never mind.
 * HOWEVER! It's probably bad to have getters and setters for every stat (which are needed to create the templates in the first place)
 * Really complicated constructors would also probably be a bad idea unless it's just (Name, Description, Stats, Actions). That might not be so bad actually.
 * 
 * Note: Was looking at factories but they seem to be more about creating sublcass instances, which would be useful if each unit type had it's own class. Which they don't
 * @author danbye50
 *
 */
public class Unit extends UnitTemplate{

	private String name;
	private int wounds, fatigue;
	private boolean shaken, recoveringShaken;
	private boolean incapacitated, bleedingOut, dead;
	private boolean canAct, canFreeAct;
	
	
	// grit
	
	//Stance enum here
	
	//Condition enum here
	
	
//	public CharSheetDisplay charSheetDisplay;

	public Unit(UnitTemplate unitType){
		// Random name here depending on unit type - static RandomNameGenerator class?
		this(unitType, "Brutha");
	}
	
	// TODO get char sheet display
	public Unit(UnitTemplate unitType, String name){
		super();
		
		this.name 	= name;	
		
		wounds 		= 0;
		fatigue 	= 0;
		
		shaken 			= false;
		recoveringShaken= false;
		incapacitated 	= false;
		bleedingOut 	= false;
		dead 			= false;
		canAct 			= true;
		canFreeAct 		= true;
		
		// Everything equals everything!
		setType(unitType.type);
		setDescription(unitType.description);
		setDisplayName(name + " the " + unitType.displayName);
		setWildcard(unitType.wildcard);
		
		setAgility(unitType.agility);
		setSmarts(unitType.smarts);
		setSpirit(unitType.spirit);
		setStrength(unitType.strength);
		setVigor(unitType.vigor);
		
		setPace(unitType.pace);
		setParry(unitType.parry);
		setToughness(unitType.toughness);
		
		setSkills(unitType.skills);
		setActions(unitType.actions);
		
		charSheetDisplay = unitType.charSheetDisplay;
	}
	

	/*
	 * Reaction methods
	 * The following methods are for one off calculations used when being attacked or taking damage.
	 *
	 */
	public void receiveMeleeAttack(Attack attack){
		// Step1: check stance and add/subtract to hit defense fund if applicable (this will happen once stance enumerator is implemented)
		System.out.println(attack.hitRoll + " attack vs. " + parry + " parry.");
		// Step2: Roll save against being hit (we are going to assume this is parry forever)
		if (attack.hitRoll >= (parry + 4)){
			System.out.println("Critical Hit!");	// DEBUG
			receiveDamage(attack.dmgRoll + Dice.roll(6));
			
		}else if(attack.hitRoll >= parry){
			System.out.println("Hit");	// DEBUG
			receiveDamage(attack.dmgRoll);
			
		}else{
			System.out.println("Miss");	// DEBUG
		}
			
	}
	public void receiveRangeAttack(Attack attack){
		// Step1: check stance and add/subtract to hit defense fund if applicable (this will happen once stance enumerator is implemented)
		System.out.println(attack.hitRoll + " attack vs. 4");
		// Step2: Roll save against being hit (we are going to assume this is 4 forever)
		if (attack.hitRoll >= (4 + 4)){
			System.out.println("Critical Hit!");	// DEBUG
			receiveDamage(attack.dmgRoll + Dice.roll(6));
		}else if(attack.hitRoll >= parry){
			receiveDamage(attack.dmgRoll);
		}else{
			System.out.println("Miss");	// DEBUG
		}
	}
	private void receiveDamage(int dmg){	
		System.out.println(dmg + " damage vs. " + toughness + " toughness.");
		if (dmg >= toughness){
			int totalDmg = (dmg - toughness)/4;	// will always be at least 1
			
			// Announcements (for the hell of it)
			switch(totalDmg){
				case 1: System.out.println("Good hit.");
				case 2: System.out.println("Deadly hit!");
				case 3: System.out.println("Unstoppable!");
				case 4: System.out.println("Godlike!");
				case 5: System.out.println("That's just mean...");
				case 6: System.out.println("Bullshit!");
			}
			
			if (shaken){
				System.out.println(displayName + " is wounded.");	// DEBUG
				wounds += totalDmg;
			}else{
				System.out.print(displayName + " is shaken");	// DEBUG
				if (totalDmg > 1) System.out.print(" and wounded"); System.out.println(".");	// DEBUG
				shaken = true;
				wounds += totalDmg - 1;	// 0 if no raises
			}
			
			if (wounds > maxWounds){
				checkIncapacitated();
			}
		}else{
			System.out.println(displayName + " shrugs off the attack.");	// DEBUG
		}		
	}
	
	private void checkIncapacitated(){
		int save = roll("vigor");
		incapacitated = true;
		if (save <= 1){
			dead = true;
			System.out.println(displayName + " has died.");	// DEBUG
		} else if (save < 4) {
			// Choose a permanent injury
			bleedingOut = true;
			System.out.println(displayName + " is incapacitated, severely injured, and bleeding out!");	// DEBUG
		} else if (save < 8) {
			// Choose a temporary injury
			System.out.println(displayName + " is incapacitated and injured.");	// DEBUG
		} else {
			// Choose 24hr/temporary injury
			System.out.println(displayName + " is incapacitated and has sutained light injuries.");	// DEBUG
		}
				
	}
	
	
	/*
	 * Turn Methods
	 * The following methods are looked at the beginning of every turn for the unit.
	 * This includes shaken checks and bleed out checks
	 * 
	 */	
	public void readyTurn(){
		// Check if unit is able to perform any actions this round
		// The UI should disable any unaccesable actions
		if (shaken){
			shaken = checkShaken();
		}
		if (bleedingOut){
			bleedingOut = checkBleedingOut();
		}
		if (dead){
			// goodbye.
			System.out.println(displayName + " is dead.");	// DEBUG
		}
	}
	
	private boolean checkShaken(){
		if (recoveringShaken){
			recoveringShaken = false;
			canAct = true;
			System.out.println(displayName + " has recovered.");	// DEBUG
			return false;
		
		} else {		
			int save = roll("spirit");
			if (save >= 8){
				canAct = true;
				System.out.println(displayName + " has recovered.");	// DEBUG
				return false;
			} else if (save >= 4){
				recoveringShaken = true;
				canAct = false;
				System.out.println(displayName + " will recover next round.");	// DEBUG
				return true;
			} else {
				canAct = false;
				System.out.println(displayName + " is still shaken.");	// DEBUG
				return true;
			}
		}
	}
	private boolean checkBleedingOut(){
		int save = roll("vigor");
		if (save >= 8){
			System.out.println(displayName + " has stopped bleeding.");
			return false;
		} else if (save >= 4){
			return true;
		} else {
			dead = true;
			System.out.println(displayName + " has bled to death.");
			return true;
		}
	}
	
	public int drawCard(CardDeck cards){	// The player is given a deck of cards and must draw one
		// TODO handle card drawing edges/hindrances here
		return cards.draw();
	}
	
	
	// Getters (and no Setters) ================================================
	
	public String getName() {
		return name;
	}
	public int getWounds() {
		return wounds;
	}
	public int getFatigue() {
		return fatigue;
	}
	
	public boolean isShaken() {
		return shaken;
	}
	public boolean isIncapacitated(){
		return incapacitated;
	}
	public boolean isBleedingOut(){
		return bleedingOut;
	}
	public boolean isDead(){
		return dead;
	}
	public boolean canAct(){
		return canAct;
	}
	public boolean canFreeAct(){
		return canFreeAct;
	}
}
